package com.js.lib.annotation.aop;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.js.lib.annotation.ApiLogger;
import com.js.lib.log.Constant;
import com.js.lib.log.LogService;
import com.js.lib.log.LogTypeEnum;
import com.js.lib.utils.DateUtils;
import com.js.lib.utils.JsonUtil;
import com.js.lib.utils.LoggerUtils;
import com.js.lib.utils.RequestUtils;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.MDC;

/**
 * 说明：日志登记拦截处理
 * @类名: LoggerAop
 *
 * @author   kenny
 * @Date	 2019年12月31日下午2:58:10
 */

@Slf4j
@Component
@Scope
@Aspect
public class ApiLoggerAop {
	/** 这个日志实现都一样，主要是为了区分写到不同的日志文件里*/
	@Resource(name="defaultLogServiceImpl")
	private LogService logService;

    @Pointcut("@annotation(com.js.lib.annotation.ApiLogger)")
    public void logpointcut() {
    	
    }
    
    //带注解的对象 apiLogger
    @Around(value = "logpointcut() && @annotation(apiLogger)")
    public Object around(ProceedingJoinPoint joinPoint,ApiLogger apiLogger) throws Throwable {
    	
    	//日志的参数
    	Map<String,Object>logParam = LoggerUtils.generalParam();
    	Object[] args = joinPoint.getArgs();
    	
    	
    	LoggerVO loggerVO = new LoggerVO();
    	loggerVO.setTime(new Date());
    	loggerVO.setIp(logParam.get("clientIp").toString());
    	if (StringUtils.isEmpty(apiLogger.apiName()))
    		loggerVO.setApiName(logParam.get("url").toString());
    	else
    		loggerVO.setApiName(apiLogger.apiName());
    	if (!StringUtils.isEmpty(logParam.get("traceCode")))
    		loggerVO.setTradeCode(logParam.get("traceCode").toString());
    	if (!StringUtils.isEmpty(logParam.get("url")))
    		loggerVO.setUrl(logParam.get("url").toString());
    	
    	if (args != null && args.length >0 ){
    		//排除ServletRequest 和 ServletResponse 参数
    		List<Object> list = new ArrayList<Object>();
     		for (Object o : args){
     			if (o instanceof ServletRequest){
     				HttpServletRequest requst = (HttpServletRequest)o;
     			}
    			if (!(o instanceof ServletRequest) && !(o instanceof ServletResponse)){list.add(o);}
    			
    		}
     		loggerVO.setData(list);
    	}
    	
    	//接口调用前
    	loggerVO.setLogType(LogTypeEnum.before);
    	log(loggerVO);
    	
    	//System.out.println("*****传入 ：" + gson.toJson(loggerVO));
    	
    	Object resultData = joinPoint.proceed(args);
    	
    	//接口调用后
    	loggerVO.setLogType(LogTypeEnum.after);
    	logParam.put("result", resultData);
    	loggerVO.setData(resultData);
    	log(loggerVO);
    	//System.out.println("*****传出 ：" + gson.toJson(loggerVO));
    	
        return resultData;
    }    
    
    private void log(LoggerVO loggerVO){
    	logService.log(loggerVO, null);
    }
    
    /**
     * 生成日志通用的数据
     * @return
     * @throws Throwable
     */
    
/*    private Map<String,Object> generalParam() {
    	
        //日志的参数
        Map<String,Object>logParam = new HashMap<String,Object>();
        
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String requestIp;
		try {
			requestIp = RequestUtils.getRequestIp(request);
			logParam.put("clientIp", requestIp);
		} catch (UnknownHostException e) {
			log.debug(">>>>> generalParam: 取客户端 IP异常");
			
		}
        String url=request.getRequestURL().toString();
        String traceCode = MDC.get(Constant.LOG_TRACE);
        
        logParam.put("traceCode", traceCode);
        logParam.put("url", url);
        log.debug(url);
         return logParam;
    }*/
    
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    public static class LoggerVO implements Serializable{
    	private static final long serialVersionUID = 1485738228112310091L;
    	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSS",timezone="GMT+8")
    	/** 时间 */
    	private Date time;
    	/** 客户端ip*/
    	private String ip;
    	/** 接口名*/
    	private String apiName;
    	/** url*/
    	private String url;
    	/** 调用接口前日志/调用接后日志*/
    	private LogTypeEnum logType;
    	/** 参数或结果数据*/
    	private Object data;
    	/** 追溯码 */
    	private String tradeCode;
    	
    	public String toString(){
    		StringBuilder sb = new StringBuilder();
    		sb.append("\r\n");
    		sb.append("time: " +  DateUtils.dateTimeMillecondFormat(this.getTime()));
    		sb.append("\r\n");
    		sb.append("Tradecode: " + this.getTradeCode());
    		sb.append("\r\n");
    		sb.append("Client Ip: " + this.getIp());
    		sb.append("\r\n");
    		sb.append("Api Name: " + this.apiName);
    		sb.append("\r\n");
    		sb.append("Api Url: " + this.getUrl());
    		sb.append("\r\n");
    		sb.append("Before/After:  " + this.getLogType());
    		sb.append("\r\n");
    		
    		if (this.data != null)
    			sb.append("data: " + JsonUtil.toJson(this.data));
    		sb.append("\r\n");
    		return sb.toString();
    	}
    }    
	
}
